<?php
declare(strict_types=1);

namespace app\service;

use app\model\{ExpressServiceProvider, ExpressPriceCache};
use think\facade\{Cache, Log};
use think\Exception;

class ExpressService extends BaseService
{
    /**
     * 验证重量是否在允许范围内
     */
    protected function validateWeight(ExpressServiceProvider $provider, float $weight): bool
    {
        if ($weight < $provider->min_weight) {
            throw new Exception("重量不能小于{$provider->min_weight}kg");
        }
        if ($weight > $provider->max_weight) {
            throw new Exception("重量不能大于{$provider->max_weight}kg");
        }
        return true;
    }

    /**
     * 计算总运费
     */
    protected function calculateTotalFee(float $weight, ExpressServiceProvider $provider, array $priceInfo): float
    {
        // 计算体积重
        $volumeWeight = 0;
        if (isset($priceInfo['length'], $priceInfo['width'], $priceInfo['height'])) {
            $volumeWeight = ($priceInfo['length'] * $priceInfo['width'] * $priceInfo['height']) / $provider->weight_index;
        }

        // 取实际重量和体积重中的较大值
        $calcWeight = max($weight, $volumeWeight);

        // 如果重量小于等于首重，只收首重费用
        if ($calcWeight <= $provider->first_weight) {
            return $priceInfo['first_price'];
        }

        // 超出首重部分，按续重计算
        $overWeight = $calcWeight - $provider->first_weight;
        return $priceInfo['first_price'] + ceil($overWeight) * $priceInfo['continued_price'];
    }

    /**
     * 计算运费
     */
    public function calculatePrice(
        string $companyCode,
        string $fromProvince,
        string $fromCity,
        string $toProvince,
        string $toCity,
        float $weight,
        ?array $volume = null // 新增体积参数
    ): array {
        try {
            // 获取快递服务商信息
            $provider = ExpressServiceProvider::where([
                'company_code' => $companyCode,
                'status' => 1
            ])->find();

            if (!$provider) {
                throw new Exception('快递服务商不存在或已禁用');
            }

            // 验证重量
            $this->validateWeight($provider, $weight);

            // 尝试从缓存获取价格
            $cacheKey = "express_price:{$companyCode}:{$fromProvince}:{$fromCity}:{$toProvince}:{$toCity}";
            $priceInfo = Cache::get($cacheKey);

            if (!$priceInfo) {
                // 从数据库获取价格
                $priceInfo = ExpressPriceCache::where([
                    'express_service_provider_id' => $provider->id,
                    'from_province' => $fromProvince,
                    'from_city' => $fromCity,
                    'to_province' => $toProvince,
                    'to_city' => $toCity
                ])->find();

                if (!$priceInfo) {
                    // 调用快递100获取价格
                    $kuaidi100Service = new Kuaidi100Service();
                    $priceInfo = $kuaidi100Service->queryPrice(
                        $companyCode,
                        $fromProvince,
                        $fromCity,
                        $toProvince,
                        $toCity
                    );

                    // 保存到缓存
                    ExpressPriceCache::create([
                        'express_service_provider_id' => $provider->id,
                        'from_province' => $fromProvince,
                        'from_city' => $fromCity,
                        'to_province' => $toProvince,
                        'to_city' => $toCity,
                        'first_price' => $priceInfo['first_price'],
                        'continued_price' => $priceInfo['continued_price']
                    ]);
                }

                // 缓存价格信息
                Cache::set($cacheKey, $priceInfo, 3600);
            }

            // 添加体积信息到价格信息中
            if ($volume) {
                $priceInfo = array_merge($priceInfo, $volume);
            }

            // 计算总运费
            $totalFee = $this->calculateTotalFee($weight, $provider, $priceInfo);

            // 计算商家利润和平台利润
            $profits = $this->calculateProfits($totalFee, $provider);

            return [
                'total_fee' => $totalFee,
                'merchant_profit' => $profits['merchant_profit'],
                'platform_profit' => $profits['platform_profit'],
                'weight_info' => [
                    'actual_weight' => $weight,
                    'volume_weight' => $volume ? ($volume['length'] * $volume['width'] * $volume['height']) / $provider->weight_index : 0,
                    'calc_weight' => max($weight, $volume ? ($volume['length'] * $volume['width'] * $volume['height']) / $provider->weight_index : 0)
                ]
            ];

        } catch (\Exception $e) {
            Log::error('计算运费失败: ' . $e->getMessage());
            throw new Exception('计算运费失败: ' . $e->getMessage());
        }
    }

    /**
     * 计算保价费
     */
    public function calculateInsureFee(string $companyCode, float $insureAmount): float
    {
        try {
            $provider = ExpressServiceProvider::where([
                'company_code' => $companyCode,
                'status' => 1
            ])->find();

            if (!$provider) {
                throw new Exception('快递服务商不存在或已禁用');
            }

            if (!$provider->is_insured) {
                throw new Exception('该快递服务商不支持保价');
            }

            return $insureAmount * ($provider->insure_fee / 100);

        } catch (\Exception $e) {
            Log::error('计算保价费失败: ' . $e->getMessage());
            throw new Exception('计算保价费失败: ' . $e->getMessage());
        }
    }

    /**
     * 计算商家利润和平台利润
     */
    protected function calculateProfits(float $totalFee, ExpressServiceProvider $provider): array
    {
        // 获取利润配置
        $profitConfig = $provider->getProfitConfig();

        // 计算商家利润
        $merchantProfit = $totalFee * ($profitConfig['merchant_profit_rate'] / 100);

        // 计算平台利润
        $platformProfit = $totalFee * ($profitConfig['platform_profit_rate'] / 100);

        return [
            'merchant_profit' => round($merchantProfit, 2),
            'platform_profit' => round($platformProfit, 2)
        ];
    }
} 